local seq = require "pl.seq"

-------------------------------------------------------------------------------
---! 内部方法
-------------------------------------------------------------------------------
local function get_welfare_daily_config(player)
    local configs = IMPORT_D:query("welfaredaily")
    if not configs then
        return
    end

    local level = player:get_level()
    return configs[level]
end

local function random_trump_welfare(config)
    local sum = 0
    for _, num in ipairs(config.trumpWelfareWeight) do
        sum = sum + num
    end

    local rate = math.random(sum)
    for idx, num in ipairs(config.trumpWelfareWeight) do
        rate = rate - num
        if rate <= 0 then
            local id = config.trumpWelfare[idx]
            if not id then
                break
            end

            local item = IMPORT_D:query("item")
            if not item[id] then
                break
            end

            return id
        end
    end
end

local function get_welfare_lucky_config(player)
    local configs = IMPORT_D:query("luckyturntable")
    if not configs then
        return
    end

    local level = player:get_level()
    return configs[level]
end

local function random_lucky_welfare(config, exclude)
    if type(exclude) ~= "table" then
        exclude = {}
    end

    local sum = 0
    for idx, num in ipairs(config.weight) do
        if not exclude[idx] then
            sum = sum + num
        end
    end

    local rate = math.random(sum)
    for idx, num in ipairs(config.weight) do
        if not exclude[idx] then
            rate = rate - num
            if rate <= 0 then
                local val = config.awards[idx]
                if not val then
                    break
                end
                return idx, val
            end
        end
    end
end

---! 获取次日凌晨
function get_next_day_time(t, day)
    local m = os.date("*t", t)
    m.day = m.day + (day or 1)
    m.hour = 0
    m.min = 0
    m.sec = 0
    return os.time(m)
end

-------------------------------------------------------------------------------
---! 对外接口
-------------------------------------------------------------------------------
WELFARE_D = {}

-------------------
---! 每日福利
-------------------

---! 获取每日福利领取次数
function WELFARE_D:get_daily_num(player, id)
    return player:query("welfare", "daily", id) or 0
end

---! 累加每日福利领取次数
function WELFARE_D:add_daily_num(player, id, offset)
    return player:set("welfare", "daily", id, player:get_welfare_daily_num(id) + (offset or 1))
end

---! 发送每日福利数据
function WELFARE_D:send_daily_data(player)
    local t = IMPORT_D:get_table("welfare")
    if not t then
        local result = {}
        result.welfare = {}
        player:send_packet("MSGS2CDailyData", result)
        return
    end

    local welfare = {}
    for i, v in pairs(t) do
        if v.isOpen == 1 then
            local m = {}
            m.id = v.id
            m.max = v.welfareNum
            m.num = player:get_welfare_daily_num(v.id)
            table.insert(welfare, m)
        end
    end

    local result = {}
    result.welfare = welfare
    player:send_packet("MSGS2CDailyData", result)
end

---! 领取每日福利奖励
function WELFARE_D:get_daily_reward(player, id)
    local t = IMPORT_D:get_table("welfare")
    if not t then
        ---! 福利配置不存在
        -- print("福利配置不存在")
        local result = {}
        result.error = 1
        player:send_packet("MSGS2CDailyReward", result)
        return
    end

    local v = t[id]
    if not v then
        ---! 不存在指定类型
        -- print("不存在指定类型")
        local result = {}
        result.error = 2
        player:send_packet("MSGS2CDailyReward", result)
        return
    end

    local num = player:get_welfare_daily_num(id)
    if num >= v.welfareNum then
        ---! 领取次数已达上限
        -- print("领取次数已达上限")
        local result = {}
        result.error = 3
        player:send_packet("MSGS2CDailyReward", result)
        return
    end

    if v.type == 4 or v.type == 5 then
        ---! 判断背包空间
        local pos = INVENTORY_D:get_trump_idle_pos(player)
        if not pos then
            ---! 背包空间已达上限
            -- print("背包空间已达上限")
            local result = {}
            result.error = 4
            player:send_packet("MSGS2CDailyReward", result)
            return
        end
    end

    local config = get_welfare_daily_config(player)
    if not config then
        ---! 福利配置不存在
        local result = {}
        result.error = 5
        player:send_packet("MSGS2CDailyReward", result)
        return
    end

    ---! 累加领取次数
    player:add_welfare_daily_num(id)

    ---! 给予每日奖励
    if v.type == 1 then
        player:add_currency(GamePropIds.kGamePropIdsCopperIcon, config.coinWelfare)

        ---! 通知领取成功
        local result = {}
        result.error = 0
        result.prop = { propId = GamePropIds.kGamePropIdsCopperIcon, propCount = INVENTORY_D:get_currency_show_count(player, GamePropIds.kGamePropIdsCopperIcon, config.coinWelfare), }
        player:send_packet("MSGS2CDailyReward", result)

        ---! 刷新货币信息
        ITEM_D:send_currency_info(player)
    elseif v.type == 2 then
        player:add_currency(GamePropIds.kGamePropIdsSoulIcon, config.soulWelfare)

        ---! 通知领取成功
        local result = {}
        result.error = 0
        result.prop = { propId = GamePropIds.kGamePropIdsSoulIcon, propCount = INVENTORY_D:get_currency_show_count(player, GamePropIds.kGamePropIdsSoulIcon, config.soulWelfare), }
        player:send_packet("MSGS2CDailyReward", result)

        ---! 刷新货币信息
        ITEM_D:send_currency_info(player)
    elseif v.type == 3 then
        player:add_currency(GamePropIds.kGamePropIdsDiamondsIcon, config.yuanbaoWelfare)

        ---! 通知领取成功
        local result = {}
        result.error = 0
        result.prop = { propId = GamePropIds.kGamePropIdsDiamondsIcon, propCount = INVENTORY_D:get_currency_show_count(player, GamePropIds.kGamePropIdsDiamondsIcon, config.yuanbaoWelfare), }
        player:send_packet("MSGS2CDailyReward", result)

        ---! 刷新货币信息
        ITEM_D:send_currency_info(player)
    elseif v.type == 4 then
        ---! 给与指定法宝
        player:add_trump(20001)

        ---! 通知领取成功
        local result = {}
        result.error = 0
        result.prop = { propId = 20001, propCount = 1, }
        player:send_packet("MSGS2CDailyReward", result)

        ---! 刷新法宝信息
        local result = {}
        result.code = 200
        result.data = player:query_trump()
        player:send_packet("MSGS2CObtainTrump", result)
    elseif v.type == 5 then
        ---! 随机法宝ID
        local propId = random_trump_welfare(config)

        ---! 给与指定法宝
        player:add_trump(propId)

        ---! 通知领取成功
        local result = {}
        result.error = 0
        result.prop = { propId = propId, propCount = 1, }
        player:send_packet("MSGS2CDailyReward", result)

        ---! 刷新法宝信息
        local result = {}
        result.code = 200
        result.data = player:query_trump()
        player:send_packet("MSGS2CObtainTrump", result)
    end

    ---! 更新每日数据
    player:send_welfare_daily_data()
end

-------------------
---! 登录奖励
-------------------

---! 获取签到天数
function WELFARE_D:get_login_days(player)
    return player:query("welfare", "login", "days") or 0
end

---! 累加签到天数
function WELFARE_D:add_login_days(player)
    return player:set("welfare", "login", "days", player:get_welfare_login_days() % 7 + 1)
end

---! 设置签到标记
function WELFARE_D:set_login_sign(player)
    player:set("welfare", "login", "sign", 1)
end

---! 获取签到标记
function WELFARE_D:get_login_sign(player)
    if player:query("welfare", "login", "sign") ~= 1 then
        return false
    end
    return true
end

---! 发送签到数据
function WELFARE_D:send_login_data(player)
    local result = {}
    result.days = player:get_welfare_login_days()
    result.sign = player:get_welfare_login_sign()
    player:send_packet("MSGS2CLoginData", result)
end

---! 领取登录奖励
function WELFARE_D:get_login_reward(player, double)
    if player:get_welfare_login_sign() then
        ---! 奖励已领取
        print("奖励已领取")
        return
    end

    local configs = IMPORT_D:query("loginaward")
    if not configs then
        ---! 配置不存在
        print("配置不存在")
        return
    end

    ---! 设置签到标记
    player:set_welfare_login_sign()

    ---! 累加签到次数
    local days = player:add_welfare_login_days()

    ---! 给予每日奖励
    local prop
    local config = configs[days]
    if config then
        local count = (double ~= 0) and config.Yuanbao * 2 or config.Yuanbao
        player:add_currency(GamePropIds.kGamePropIdsDiamondsIcon, count)

        prop = {}
        prop.propId = GamePropIds.kGamePropIdsDiamondsIcon
        prop.propCount = count
    end

    ---! 通知领取成功
    local result = {}
    result.error = 0
    result.prop = prop
    player:send_packet("MSGS2CLoginReward", result)
    ITEM_D:send_currency_info(player)
    ---! 更新登录数据
    player:send_welfare_login_data()
end

-------------------
---! 幸运抽奖
-------------------

---! 发送幸运抽奖数据
function WELFARE_D:send_lucky_data(player)
    local result = {}
    result.num = WELFARE_D:get_lucky_num(player)
    result.count = WELFARE_D:get_lucky_count(player)
    result.times = WELFARE_D:get_lucky_times(player)
    player:send_packet("MSGS2CLuckyData", result)
end

---! 获取幸运抽奖次数
function WELFARE_D:get_lucky_num(player)
    local num = player:query("welfare", "lucky", "num")
    if num then
        return num
    end

    local config = IMPORT_D:query("common")
    if not config then
        return 0
    end

    local num = config.dailyTurntableNum
    if not num then
        return 0
    end

    return player:set("welfare", "lucky", "num", num)
end

---! 扣除幸运抽奖次数
function WELFARE_D:cost_lucky_num(player, offset)
    offset = offset or 1
    local num = WELFARE_D:get_lucky_num(player)
    if num < offset then
        return
    end
    return player:set("welfare", "lucky", "num", num - offset)
end

---! 累加幸运抽奖次数
function WELFARE_D:add_lucky_num(player, offset)
    offset = offset or 1
    local num = WELFARE_D:get_lucky_num(player)
    return player:set("welfare", "lucky", "num", num + offset)
end

---! 获取幸运抽奖广告次数
function WELFARE_D:get_lucky_count(player)
    local count = player:query("welfare", "lucky", "count")
    if count then
        return count
    end

    local config = IMPORT_D:query("common")
    if not config then
        return 0
    end

    if type(config.TurntableAdd) ~= "table" then
        return 0
    end

    if #config.TurntableAdd ~= 2 then
        return 0
    end

    local count = config.TurntableAdd[1]
    if not count then
        return 0
    end

    return player:set("welfare", "lucky", "count", count)
end

---! 扣除幸运抽奖广告次数
function WELFARE_D:cost_lucky_count(player, offset)
    offset = offset or 1
    local num = WELFARE_D:get_lucky_count(player)
    if num < offset then
        return
    end
    return player:set("welfare", "lucky", "count", num - offset)
end

---! 获取幸运抽奖奖励倍数
function WELFARE_D:get_lucky_times(player)
    return player:query("welfare", "lucky", "times") or 1
end

---! 设置幸运抽奖奖励倍数
function WELFARE_D:set_lucky_times(player, times)
    return player:set("welfare", "lucky", "times", times)
end

---! 领取幸运抽奖奖励
function WELFARE_D:get_lucky_reward(player, index)
    if not index or index == 0 or index % 4 ~= 0 then
        if WELFARE_D:get_lucky_num(player) <= 0 then
            return
        end

        local config = get_welfare_lucky_config(player)
        if not config then
            ---! 福利配置不存在
            return
        end

        ---! 扣除幸运抽奖广告次数
        WELFARE_D:cost_lucky_num(player)

        local exclude
        local times = WELFARE_D:get_lucky_times(player)
        if times > 1 then
            WELFARE_D:set_lucky_times(player, 1)
            exclude = { [4] = true, [8] = true, }
        end

        ---! 幸运抽奖
        local idx, val = random_lucky_welfare(config, exclude)

        local type = idx % 4
        if type == 0 then
            ---! 设置幸运抽奖奖励倍数
            player:set_temp("welfare_lucky_times", tonumber(tostring(val)))

            ---! 通知领取成功
            local result = {}
            result.error = 0
            result.index = idx
            player:send_packet("MSGS2CLuckyReward", result)

            ---! 更新每日数据
            WELFARE_D:send_lucky_data(player)
            return
        end

        local prop
        local count = val * times
        if type == 1 then
            player:add_currency(GamePropIds.kGamePropIdsCopperIcon, count)
            prop = { propId = GamePropIds.kGamePropIdsCopperIcon, propCount = INVENTORY_D:get_currency_show_count(player, GamePropIds.kGamePropIdsCopperIcon, count), }
        elseif type == 2 then
            player:add_currency(GamePropIds.kGamePropIdsSoulIcon, count)
            prop = { propId = GamePropIds.kGamePropIdsSoulIcon, propCount = INVENTORY_D:get_currency_show_count(player, GamePropIds.kGamePropIdsSoulIcon, count), }
        elseif type == 3 then
            player:add_currency(GamePropIds.kGamePropIdsDiamondsIcon, count)
            prop = { propId = GamePropIds.kGamePropIdsDiamondsIcon, propCount = INVENTORY_D:get_currency_show_count(player, GamePropIds.kGamePropIdsDiamondsIcon, count), }
        end

        ---! 通知领取成功
        local result = {}
        result.error = 0
        result.index = idx
        result.prop = prop
        player:send_packet("MSGS2CLuckyReward", result)
        ITEM_D:send_currency_info(player)
    else
        local times = player:query_temp("welfare_lucky_times")
        if not times then
            return
        end

        ---! 设置倍数
        WELFARE_D:set_lucky_times(player, times)

        ---! 通知领取成功
        local result = {}
        result.error = 0
        result.index = 0
        player:send_packet("MSGS2CLuckyReward", result)
    end

    ---! 清除倍数标识
    player:delete_temp("welfare_lucky_times")

    ---! 更新每日数据
    WELFARE_D:send_lucky_data(player)
end

---! 增加幸运抽奖次数
function WELFARE_D:get_lucky_add(player)
    local count = WELFARE_D:get_lucky_count(player)
    if count <= 0 then
        return
    end

    local config = IMPORT_D:query("common")
    if not config then
        return
    end

    if type(config.TurntableAdd) ~= "table" then
        return
    end

    if #config.TurntableAdd ~= 2 then
        return
    end

    local num = config.TurntableAdd[2]
    if not num then
        return
    end

    ---! 扣除添加次数
    WELFARE_D:cost_lucky_count(player)

    ---! 增加抽奖次数
    WELFARE_D:add_lucky_num(player, num)

    ---! 刷新抽奖信息
    WELFARE_D:send_lucky_data(player)
end

-------------------
---! 离线奖励
-------------------

---! 发送离线奖励数据
function WELFARE_D:send_offline_data(player)
    ---! 获取离线时长
    local duration = player:query("welfare", "offline", "duration")
    if not duration then
        return
    end

    local config = get_welfare_daily_config(player)
    if not config then
        ---! 福利配置不存在
        return
    end

    ---! 离线时间=上线时间-上次离线时间，离线时间大于360分钟的取360分钟，最多奖励360分钟离线奖励
    local offline = math.min(21600, duration)
    local count = config.offLineWelfare * offline

    ---! 通知客户端领取奖励
    local result = {}
    result.offline = offline
    result.prop = { propId = GamePropIds.kGamePropIdsCopperIcon, propCount = INVENTORY_D:get_currency_show_count(player, GamePropIds.kGamePropIdsCopperIcon, count), }
    player:send_packet("MSGS2COfflineData", result)
end

---! 领取离线奖励
function WELFARE_D:get_offline_reward(player, double)
    ---! 获取离线时长
    local duration = player:query("welfare", "offline", "duration")
    if not duration then
        return
    end

    local config = get_welfare_daily_config(player)
    if not config then
        ---! 福利配置不存在
        return
    end

    ---! 清理当前离线数据
    player:delete("welfare", "offline")

    ---! 离线时间=上线时间-上次离线时间，离线时间大于360分钟的取360分钟，最多奖励360分钟离线奖励
    local duration = math.min(21600, duration)
    if double and double > 0 then
        duration = duration * 2
    end
    local count = config.offLineWelfare * duration

    ---! 给与离线奖励
    player:add_currency(GamePropIds.kGamePropIdsCopperIcon, count)

    ---! 通知领取成功
    local result = {}
    result.error = 0
    result.isDouble = double
    result.prop = { propId = GamePropIds.kGamePropIdsCopperIcon, propCount = INVENTORY_D:get_currency_show_count(player, GamePropIds.kGamePropIdsCopperIcon, count), }
    player:send_packet("MSGS2COfflineReward", result)
    ITEM_D:send_currency_info(player)
end

-------------------
---! 明日礼包
-------------------

---! 发送明日礼包数据
function WELFARE_D:send_tomorrow_data(player)
    local configs = IMPORT_D:query("box")
    if not configs then
        return
    end

    local create_time = player:get_create_time()
    if not create_time then
        return
    end

    local gifts = {}
    for _, config in pairs(configs) do
        local gift = {}
        gift.id = config.id
        gift.time = get_next_day_time(create_time, config.day - 1)
        if config.rewardConf1 == "player" then
            gift.flag = player:get_partner(config.rewardId1) and 1 or 0
        elseif config.rewardConf1 == "wing" then
            local wing = WING_D:find_wing(config.rewardId1)
            gift.flag = player:get_wing_level(wing.wingid) and 1 or 0
        elseif config.rewardConf1 == "sw" then
            local artifact = ARTIFACT_D:find_artifact(config.rewardId1)
            gift.flag = player:get_artifact_level(artifact.swid) and 1 or 0
        end
        table.insert(gifts, gift)
    end

    local result = {}
    result.gifts = gifts
    player:send_packet("MSGS2CTomorrowData", result)
end

---! 领取明日礼包奖励
function WELFARE_D:get_tomorrow_reward(player, id)
    local configs = IMPORT_D:query("box")
    if not configs then
        return
    end

    local config = configs[id]
    if not config then
        return
    end

    local create_time = player:get_create_time()
    if not create_time then
        return
    end

    local draw_time = get_next_day_time(create_time, config.day - 1)
    if os.time() < draw_time then
        local result = {}
        result.id = id
        result.error = 1
        player:send_packet("MSGS2CTomorrowReward", result)
        return
    end

    if config.rewardConf1 == "player" then
        if player:get_partner(config.rewardId1) then
            local result = {}
            result.id = id
            result.error = 2
            player:send_packet("MSGS2CTomorrowReward", result)
            return
        end

        ---! 次日登陆，获得“小仙女（貂蝉红）”
        player:add_partner(config.rewardId1)

        ---! 重新刷新伙伴数据
        PARTNER_D:send_partner_info(player)

        ---! 同步伙伴排名
        RANK_D:sync_rank_data(player, "partner_rank")
    elseif config.rewardConf1 == "wing" then
        local wing = WING_D:find_wing(config.rewardId1)
        if not wing then
            local result = {}
            result.id = id
            result.error = 3
            player:send_packet("MSGS2CTomorrowReward", result)
            return
        end

        if player:get_wing_level(wing.wingid) then
            local result = {}
            result.id = id
            result.error = 4
            player:send_packet("MSGS2CTomorrowReward", result)
            return
        end

        ---! 解锁当前翅膀
        player:set_wing_level(wing.wingid, wing.level)

        ---! 刷新翅膀列表
        WING_D:send_wing_info(player)

        ---! 同步伙伴排名
        RANK_D:sync_rank_data(player, "wings_rank")
    elseif config.rewardConf1 == "sw" then
        local artifact = ARTIFACT_D:find_artifact(config.rewardId1)
        if not artifact then
            local result = {}
            result.id = id
            result.error = 5
            player:send_packet("MSGS2CTomorrowReward", result)
            return
        end

        if player:get_artifact_level(artifact.swid) then
            local result = {}
            result.id = id
            result.error = 6
            player:send_packet("MSGS2CTomorrowReward", result)
            return
        end

        ---! 解锁当前神器
        player:set_artifact_level(artifact.swid, artifact.level)

        ---! 刷新神器列表
        ARTIFACT_D:send_artifact_info(player)

        ---! 同步伙伴排名
        RANK_D:sync_rank_data(player, "artifact_rank")
    end

    ---! 通用奖励
    player:add_currency(config.rewardId2, config.rewardNum2)
    player:add_currency(config.rewardId3, config.rewardNum3)
    ITEM_D:send_currency_info(player)

    ---! 通知客户端领取奖励
    local result = {}
    result.id = id
    result.error = 0
    player:send_packet("MSGS2CTomorrowReward", result)

    ---! 刷新明日礼包
    -- WELFARE_D:send_tomorrow_data(player)
end

-------------------------------------------------------------------------------
---!
-------------------------------------------------------------------------------
function WELFARE_D:send_welfare_info(player)
    WELFARE_D:send_daily_data(player)
    WELFARE_D:send_login_data(player)
    WELFARE_D:send_lucky_data(player)
    WELFARE_D:send_offline_data(player)
    WELFARE_D:send_tomorrow_data(player)
end

-------------------------------------------------------------------------------
---! 启动接口
-------------------------------------------------------------------------------
register_post_init(function()
    USER_D:register_enter_world("welfare", function(player)
        ---! 获取登出时间
        local logout = player:query("welfare", "offline", "logout")
        if not logout then
            return
        end

        ---! 缓存上次登出时间
        player:set_temp("welfare", "offline", "logout", logout)

        ---! 清理登出时间
        player:delete("welfare", "offline", "logout")

        ---! 累计离线时长
        local offline = os.time() - logout
        if offline < 300 then
            return
        end

        ---! 获取离线时长
        local duration = player:query("welfare", "offline", "duration") or 0

        ---!记录离线时长
        player:set("welfare", "offline", "duration", duration + offline)
    end)

    USER_D:register_leave_world("welfare", function(player)
        ---! 记录当前登出时间
        player:set("welfare", "offline", "logout", os.time())
    end)
end)
